1. 阿里巴巴Java代码开发手册部分注意点笔记
嵩山版
2. 强制
抽象类名用Abstract开头。
类名使用首字母大写的驼峰命名风格,但以下情形除外:DO/BO/DTO/VO/AO/PO/UID等。
POJO类的任何布尔类型的变量都不要加is前缀,否则部分框架解析会引起序列化错误。
个人理解是该布尔类型变量生成的getter方法名会和变量名重复。
boolean的变量生成方法名的前缀是is_xxx
Boolean的变量生成方法名的前缀是get_xxx
MySQL中表达是否变量采用is_xxx形式,需要在
<resultMap>
设置从is_xxx到xxx的映射关系。包名单数形式,类名如果有复数含义可以用复数形式。
所有的复写方法,必须加
@Override
注解。判断对象是否相等应用常量或者有确定的值来调用
equals()
方法。推荐使用JDK7引入的工具类
java.util.Objects#equals(Object a, Object b)
。所有整型包装类对象之间值的比较,全部采用equals方法。
Integer a = 1; Integer b = 1; System.out.println(a == b); // true System.out.println(a.equals(b)); // true Integer c = 128; Integer d = 128; System.out.println(c == d); // false System.out.println(c.equals(d)); // true
原因:Integer类中有IntegerCache静态方法,里面有存放-127-128的cache[],当包装类的Integer值为-127-128,会返回cache中的地址。超出该范围会new对象,从而地址发生不同。
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; //... // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
任何货币金额,均以最小货币单位且以整型类型来进行存储。
浮点数之间的等值判断,基本数据类型不可以用==判断,包装数据类型不可以用equals()判断。应该用BigDecimal类的compareTo方法。
equals方法会比较值和精度,compareTo会忽略精度。
所有POJO类属性必须使用包装数据类型。
日期格式化时,传入pattern中表示年份统一使用小写的y。"yyyy-MM-dd HH:mm:ss"
yyyy表示当天所在的年,YYYY代表的是当天所在的周属于的年份,一周从周日开始,周六结束。只要本周跨年,返回的YYYY就是下一年。
获取当前毫秒数要用System.currentTimeMillis(),而不是new Date().getTime()。
// 获取今年的天数 int dayOfThisYear = LocalDate.now().lengthOfYear(); // 获取指定某年的天数 LocalDate.of(2021, 8, 2).lengthOfYear();
只要重写equals,就必须重写hashCode。
判断集合是否为空使用isEmpty(),而不是比较size(),提高效率,可读性好。
在使用java.util.stream.Collectors类的toMap()方法转为Map集合时,要使用含有参数类型为BinaryOperator, 参数名为mergeFunction的方法。否则当key相同时,会出现异常。
// ArrayList pairArrayList Map<?, ?> map = pairArrayList.stream().collect( Collectors.toMap(Pair::getKey, Pair::getValue, (v1, v2) -> v2) );
集合转数组的方法,必须使用集合的toArray(T[] array),传入的是类型完全一致,长度为0的空数组。
ArrayList<String> strings = new ArrayList<>(); strings.add("123"); /* public <T> T[] toArray(T[] a) 以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。 如果列表适合指定的数组,则返回其中。 否则,将为指定数组的运行时类型和此列表的大小分配一个新数组。 参数 a - 要存储列表的元素的数组,如果它够大; 否则,为此目的分配相同运行时类型的新数组。 */ String[] array = strings.toArray(new String[0]); System.out.println(array);
不要再foreach循环里进行元素的remove/add操作。remove元素使用Iterator方式,如果并发操作需要对Iterator对象加锁。
线程池不允许使用Executors创建,而是通过ThreadPoolExecutor创建,可以规避资源耗尽。
多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其他任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。
switch块中,最后需要有default语句,即使它什么代码都没有。
当switch括号内的变量类型为String并且此变量为外部参数时,必须先进行null判断。
高并发场景中,避免使用“等于”判断作为中断或退出的条件。
所有的枚举类型字段必须要有注释,说明每个数据项的用途。
服务端发生错误时,返回给前端的响应信息必须包含HTTP状态码、errorCode、errorMessage、用户提示信息四个部分。
对于需要使用超大整数返回前端的场景,服务端一律使用String字符串类型返回,禁止使用Long类型。
HTTP请求通过URL传递参数时,不能超过2048字节。
翻页场景中,输入参数小于1,前端返回第一页参数给后端;后段发现用户输入的参数大于总页数,直接返回最后一页。
服务器内部重定向必须使用forward;外部重定向地址必须使用URL统一代理模块生成,否则会因线上采用HTTPS协议而导致浏览器提示“不安全”,并且还会带来URL维护不一致的问题。
后台输送给页面的变量必须加
$!{var}
——中间的感叹号。如果var为null或者不存在,那么
${var}
会直接显示在页面上。Math.random()返回double类型,取值范围为
0<=x<1
,可以取到0(注意除0异常),如果想获取整数类型的随机数,不要将x放大10的若干倍然后取整,直接使用Random对象的nextInt或者nextLong方法。错误码为字符串类型,共5位,分成两个部分:错误产生来源+四位数字编号。
错误产生来源分为 A/B/C,A 表示错误来源于用户,比如参数错误,用户安装版本过低,用户支付 超时等问题;B 表示错误来源于当前系统,往往是业务逻辑出错,或程序健壮性差等问题;C 表示错误来源 于第三方服务,比如 CDN 服务出错,消息投递超时等问题;四位数字编号从 0001 到 9999,大类之间的步长间距预留 100
事务场景中,抛出异常被catch后,如果需要回滚,一定要注意手动回滚事务。
不要在finally块中使用return。
所有日志文件至少保存15天,因为有些异常具备以“周”为频次发生的特点。对于 当天日志,以“应用名.log”来保存,保存在/home/admin/应用名/logs/目录下,过往日志 格式为: {logname}.log.{保存日期},日期格式:yyyy-MM-dd
根据国家法律,网络运行状态、网络安全事件、个人敏感信息操作等相关记录,留存 的日志不少于六个月,并且进行网络多机备份。
表达是与否概念的字段,必须使用is_xxx 的方式命名,数据类型是 unsigned tinyint(1 表示是,0 表示否)。
表名不使用复数名词。
主键索引名为
pk_字段名
;唯一索引名为uk_字段名
;普通索引名则为idx_字段名。表必备三字段:id,create_time,update_time。
页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。
不要使用count(列名)或count(常量)来替代count(),count()是SQL92定义的标 准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。 说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行
代码中写分页查询逻辑时,若count为0应直接返回,避免执行后面的分页语句。
数据订正(特别是删除或修改记录操作)时,要先select,避免出现误删除,确认无 误才能执行更新语句。
对于数据库中表记录的查询和变更,只要涉及多个表,都需要在列名前加表的别名(或 表名)进行限定。 说明:对多表进行查询记录、更新记录、删除记录时,如果对操作列没有限定表的别名(或表名),并且 操作列在多个表中存在时,就会抛异常。
正例:
select t1.name from table_first as t1 , table_second as t2 where t1.id=t2.id;
反例:在某业务中,由于多表关联查询语句没有加表的别名(或表名)的限制,正常运行两年后,最近在 某个表中增加一个同名字段,在预发布环境做数据库变更后,线上查询语句出现出 1052 异常:
Column 'name' in field list is ambiguous。
在表查询中,一律不要使用 * 作为查询的字段列表,需要哪些字段必须明确写明。
说明:1)增加查询分析器解析成本。2)增减字段容易与 resultMap 配置不一致。3)无用字段增加网络 消耗,尤其是 text 类型的字段。
sql.xml 配置参数使用:#{},#param# 不要使用${} 此种方式容易出现 SQL 注入。
更新数据表记录时,必须同时更新记录对应的update_time字段值为当前时间。
不得使用外键与级联,一切外键概念必须在应用层解决。